# $Id: models.py 7557b5d4d82b 2012/12/02 09:07:16 pgurumur $
# Copyright (c) 2009 Prabhu Gurumurthy  <pgurumur@gmail.com>
# 
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

import datetime

from django.contrib.auth.models import User
from django.db import models

from djanet.db import models as model
from djanet.db import choices, fields, netdb
from djanet.lib import stdlib

class SnmpVersion(fields.Enumeration):
   snmpv1 = fields.Enum(1, 'snmpv1', 'SNMP version 1')
   snmpv2 = fields.Enum(2, 'snmpv2', 'SNMP version 2')
   snmpv3 = fields.Enum(3, 'snmpv3', 'SNMP version 3')

class SnmpV3Auth(fields.Enumeration):
   authnone = fields.Enum(0, 'none', 'No Auth')
   authsha = fields.Enum(1, 'sha', 'SHA Auth')
   authmd5 = fields.Enum(2, 'md5', 'MD5 Auth')

class SnmpV3Enc(fields.Enumeration):
   encnone = fields.Enum(0, 'enum', 'No Encryption')
   encaes = fields.Enum(1, 'aes', 'AES 128 Encryption')
   encaes192 = fields.Enum(2, 'aes-192', 'AES 192 Encryption')
   encaes256 = fields.Enum(3, 'aes-256', 'AES 256 Encryption')
   enc3des = fields.Enum(4, 'triple-des', '3DES Encryption')
   encdes = fields.Enum(5, 'des', 'DES Encryption')

class IGPOspf(model.BaseModel):
   area = model.IPAddressField(help_text = "OSPF area used", name = "area")
   password = model.CryptField(help_text = "OSPF password used",
         name = "password")
   authtype = models.CharField(max_length = 10,
         choices = choices.OSPF_AUTH_TYPES,
         help_text = "OSPF Authentication types")

   class Meta:
      db_table = u'igp_ospf'

   def __str__(self):
      return stdlib.my_str(self.area)

class IGPIsIs(model.BaseModel):
   name = models.CharField(max_length = 25, help_text = "IS-IS name used",
         name = "name")
   password = model.CryptField(help_text = "IS-IS password used",
         name = "password")

   class Meta:
      db_table = u'igp_isis'

   def __str__(self):
      return stdlib.my_str(self.name)

class SnmpModel(model.BaseModel):
   version = fields.EnumField(SnmpVersion)
   snmpv3_auth = fields.EnumField(SnmpV3Auth)
   snmpv3_enc = fields.EnumField(SnmpV3Enc)
   snmp_read = models.CharField(max_length = 50, name = "snmp_read",
         help_text = "SNMP RO community", null = True, blank = True,
         unique = True)
   snmp_write = model.CryptField(help_text = "SNMP RW community",
         name = "snmp_write", null = True, blank = True, unique = True)
   snmp_auth = model.CryptField(help_text = "SNMP Auth passphrase",
         name = "snmp_auth", null = True, blank = True, unique = True)
   snmp_priv = model.CryptField(help_text = "SNMP Priv passphrase",
         name = "snmp_priv", null = True, blank = True, unique = True)
   snmp_user = models.CharField(max_length = 18, name = "snmp_user",
         help_text = "SNMP v3 username", null = True, blank = True,
         unique = True)

   class Meta:
      db_table = u'snmp_version'

   def __str__(self):
      return stdlib.my_str(self.version)

   def save(self, *args, **kwargs):
      if not (self.snmpv3_auth and self.snmpv3.enc) and len(self.snmp_priv):
         raise model.ModelError("Need both auth and encryption to be defined!")
      
      super(SnmpModel, self).save(*args, **kwargs)

class Compartment(model.BaseModel):
   site = models.ForeignKey(netdb.Site)
   cmpt_name = models.CharField(max_length = 15, help_text = "Compartment name")
   active = models.BooleanField(help_text = "Compartment active",
         name = "cmpt_active")
   enable = model.CryptField(help_text = "enable password for compartment",
         name = "cmpt_enable", unique = True)
   bgp_as = models.IntegerField(null = True, help_text = "BGP AS number",
         name = "cmpt_bgpas", blank = True)
   igp_passwd = model.CryptField(help_text = "IGP Password", blank = True,
         null = True, name = "igp_passwd")
   igp_used = models.CharField(max_length = 10,
         choices = choices.IGP_PROTOCOLS, help_text = 'Routing protocol used')
   vtp_passwd = model.CryptField(help_text = "VTP Password",
         name = "vtp_passwd", blank = True, null = True, unique = True)
   vtp_device = models.ForeignKey(netdb.Device, null = True, blank = True)
   vtp_domain = models.CharField(help_text = "VTP domain name", blank = True,
         null = True, name = "vtp_domain", max_length = 30)
   snmp = models.ForeignKey(SnmpModel)

   class Meta:
      db_table = u'compartment'
      ordering = ['cmpt_name']

   def __init__(self, *args, **kwargs):
      self._bgpMaxAs = 65535
      super(Compartment, self).__init__(*args, **kwargs)

   def __str__(self):
      return stdlib.my_str(self.cmpt_name)

   def save(self, *args, **kwargs):
      if self.bgp_as > self._bgpMaxAs:
         raise model.ModelError, "invalid BGP AS number"

      super(Compartment, self).save(*args, **kwargs)

   IsActive = property(fget = lambda self: bool(self.active))

class CompartmentUser(model.BaseModel):
   compartment = models.ForeignKey(Compartment)
   username = models.ForeignKey(User)

   class Meta:
      db_table = u'cmpt_user'

   def __str__(self):
      return stdlib.my_str("<%s: %s>" %(self.compartment, self.user))

class DeviceLocation(model.BaseModel):
   compartment = models.ForeignKey(Compartment)
   device = models.ForeignKey(netdb.Device)

   class Meta:
      db_table = u'device_location'
      ordering = ['compartment', 'device']

   def __str__(self):
      return stdlib.my_str("(%s %s)" %(self.compartment, self.device))

class DeviceLogin(model.BaseModel):
   username = models.CharField(max_length = 15,
         help_text = "Username for the device", name = "device_user")
   password = model.CryptField(help_text = "Password for the device",
         name = "device_passwd")
   login_method = models.CharField(max_length = 10,
         choices = choices.LOGIN_METHODS, help_text = 'Login method used')
   device = models.ForeignKey(netdb.Device)

   class Meta:
      db_table = u'device_login'
      ordering = ['username', 'device']

   def __str__(self):
      return stdlib.my_str("(%s %s)" %(str(self.username), str(self.device)))

class BackupInfo(model.BaseModel):
   tftp_server = model.IPAddressField(help_text = "TFTP server",
         name = "tftp_server")
   device = models.ForeignKey(netdb.Device)

   class Meta:
      db_table = u'backup_info'

   def __str__(self):
      return stdlib.my_str(self.device)

class ConfigBackup(model.BaseModel):
   device = models.ForeignKey(netdb.Device)
   credentials = models.ForeignKey(DeviceLogin)
   digest = models.CharField(unique = True, max_length = 128,
         help_text = "Authentication digest", name = "conf_digest")
   backup_time = models.DateTimeField(
         help_text = "Last device backup time", name = "backup_time")

   class Meta:
      db_table = u'device_backup'
      ordering = ['device']

   def __str__(self):
      return stdlib.my_str(self.device)

   def LastBackup(self):
      return stdlib.my_str(self.backup_time)

   def save(self, *args, **kwargs):
      self.backup_time = datetime.datetime.now()
      super(ConfigBackup, self).save(*args, **kwargs)

class Failover(model.BaseModel):
   compartment = models.ForeignKey(Compartment)
   password = model.CryptField(help_text = "Failover password", unique = True)
   primary = model.IPAddressField(help_text = "IPv4 address of primary",
         name = "primary_ip")
   secondary = model.IPAddressField(help_text = "IPv4 address of secondary",
         name = "secondary_ip")
   primary_sip = model.IPAddressField(
         help_text = "IPv4 address of the primary statelink",
         name = "primary_statelink", null = True, blank = True)
   secondary_sip = model.IPAddressField(
         help_text = "IPv4 address of the primary statelink",
         name = "secondary_statelink", null = True, blank = True)

   class Meta:
      db_table = u'fw_failover'
      ordering = ['primary', 'secondary', 'compartment']

   def __str__(self):
      return stdlib.my_str(self.device)

class CompartmentAddress(model.BaseModel):
   compartment = models.ForeignKey(Compartment)
   ipv4 = models.ForeignKey(netdb.Ipblock,
         related_name = "%(class)s_related_ipv4", unique = True)
   ipv6 = models.ForeignKey(netdb.Ipblock,
         related_name = "%(class)s_related_ipv6", null = True, blank = True,
         unique = True)

   class Meta:
      db_table = u'cmpt_address'

   def __str__(self):
      return stdlib.my_str("%s - %s" %(str(self.compartment), str(self.ipv4)))

class DeviceTrapReceiver(model.BaseModel):
   device = models.ForeignKey(netdb.Device)
   trap_host = model.IPAddressField(name = "trap_host",
         help_text = "Trap receiver for the device")

   class Meta:
      db_table = u'snmptrap_recv'

   def __str__(self):
      return stdlib.my_str(self.trap_host)

class CompartmentVlan(model.BaseModel):
   vlanid = models.IntegerField(null = True, help_text = "Vlan number",
         name = "vlan_id")
   name = models.CharField(max_length = 128, help_text = "Vlan name",
         name = "vlan_name")
   compartment = models.ForeignKey(Compartment)
   ipv4 = models.ForeignKey(netdb.Ipblock,
         related_name = "%(class)s_related_ipv4", null = True, blank = True,
         unique = True)
   ipv6 = models.ForeignKey(netdb.Ipblock,
         related_name = "%(class)s_related_ipv6", null = True, blank = True,
         unique = True)

   class Meta:
      db_table = u'cmpt_vlan'

   def __str__(self):
      return stdlib.my_str(self.name)

   def save(self, *args, **kwargs):
      if self.vlanid > 4094:
         raise ModelError, "Vlan Id too high!"

      super(CompartmentVlan, self).save(*args, **kwargs)
